<?php
/**
 * Copyright 2011  SURFfoundation
 * 
 * This file is part of ESCAPE.
 * 
 * ESCAPE is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * ESCAPE is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with ESCAPE.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * For more information:
 * http://escapesurf.wordpress.com/
 * http://www.surffoundation.nl/
 * 
 * Contact: d.vierkant@utwente.nl
 * 
 * @license http://www.gnu.org/licenses/gpl.html GNU GPLv3
 */
?>
<?php

// Examples
// simple crossref query result:
// http://www.crossref.org/openurl/?pid=zter:zter321&url_ver=Z39.88-2004&rft_id=info:doi/10.1109/ISCAS.1993.393972&format=xsl_xml&redirect=false
// full crossref query result:
// http://www.crossref.org/openurl/?pid=zter:zter321&url_ver=Z39.88-2004&rft_id=info:doi/10.1109/ISCAS.1993.393972&format=unixref&redirect=false

/**
 * DOI metadata extractor
 * 
 * Extracts metadata by searching for DOIs in the (X)HTML content and fetching the metadata from CrossRef
 */
class metaextractor_extractor_Doi extends metaextractor_Extractor
{
	protected $name = "DOI";
	protected $supportedUrlPattern = null;
	
	/**
	 * (non-PHPdoc)
	 * @see escape/metaextractor/extractor/metaextractor_Extractor::processUrl()
	 */
	public function processUrl($url, $urlContentFetcher)
	{
		$results = array();
		$metadataDocuments = array();
		
		$urlContent = $urlContentFetcher->getUrlContent($url);
		
		// try to get a more accurate subject URI from the HTTP headers
		$httpHeaders = $urlContent->getHttpHeaders();
		$subjectUri = metaextractor_Util::extractPrimaryTopicUriFromHttpHeaders($httpHeaders, $url);
		
		// only accept complete (X)HTML pages
		$mimeType = $urlContent->getMimeType();
		if($urlContent->isComplete() && ($mimeType == 'text/html' || $mimeType == 'application/xhtml+xml')) // perhaps also 'application/xml' and 'text/xml'
		{
			// fetch the text content in UTF8
			$html = $urlContent->getUtf8TextContent();
			
			// try to get a more accurate subject URI from the (X)HTML content
			if($subjectUri === null)
			{
				$subjectUri = metaextractor_Util::extractPrimaryTopicUriFromHtml($html, $url);
			}
			
			// use the URL as the subject URI if no subject URI was extracted
			if($subjectUri === null)
			{
				$subjectUri = $url;
			}
			
			// find DOIs in the page
			preg_match_all('/(10.(\d)+\\/([^(\s\>\"\<)])+)/im', $html, $matches);
			//print_r($matches);
			$dois = $matches[0];
			$dois = array_unique($dois);
			//print_r($dois);
			
			// loop over all DOIs
			foreach($dois as $doi)
			{
				// convert the DOIs to plain text
				$doi = html_entity_decode($doi);
				$doi = urldecode($doi);

				// fetch metadata from Crossref
				$crossrefUrl = 'http://www.crossref.org/openurl/?pid=zter:zter321&url_ver=Z39.88-2004&format=xsl_xml&redirect=false&rft_id=info:doi/' . rawurlencode($doi);
				
				$crossrefResult = null;
				try
				{
					$crossrefResult = $urlContentFetcher->getUrlContent($crossrefUrl);
				}
				catch(metaextractor_exception_Exception $exception)
				{
					// ignore the exception
				}
				
				// only accept complete content
				if($crossrefResult!== null && $crossrefResult->isComplete())
				{
					// parse the Crossref result set
					$doc = new DOMDocument();
					$domLoadSuccess = $doc->loadXML($crossrefResult->getContent());
					if($domLoadSuccess)
					{
						$xpath = new DOMXpath($doc);
						$xpath->registerNamespace('qr', 'http://www.crossref.org/qrschema/2.0');
						
						$elements = $xpath->query("/qr:crossref_result/qr:query_result/qr:body/qr:query");
						if($elements->length > 0)
						{
							$queryElement = $elements->item(0);
							
							$queryStatus = $queryElement->getAttribute('status');
							if($queryStatus == 'resolved')
							{
								// create a result document
								$rdfDocument = simplerdf_RdfDocument::createRdfDocument();
								$rdfResource = $rdfDocument->createResource($subjectUri);
								
								// title
								$elements = $xpath->query("qr:article_title", $queryElement);
								if($elements->length > 0)
								{
									$objects = array();
									foreach($elements as $element)
									{
										/* @var $element DOMNode */
										$objects[] = $element->nodeValue;
									}
									$rdfResource->addStatement('http://purl.org/dc/terms/title', $objects);
								}
								else
								{
									$elements = $xpath->query("qr:volume_title", $queryElement);
									if($elements->length > 0)
									{
										$objects = array();
										foreach($elements as $element)
										{
											/* @var $element DOMNode */
											$objects[] = $element->nodeValue;
										}
										$rdfResource->addStatement('http://purl.org/dc/terms/title', $objects);
									}
								}

								// contributors
								$elements = $xpath->query("qr:contributors/qr:contributor", $queryElement);
								if($elements->length > 0)
								{
									$objects = array();
									foreach($elements as $element)
									{
										/* @var $element DOMNode */
										$contributorRole = $element->attributes->getNamedItem('contributor_role');

										$person = $rdfDocument->createResource();
										$person->setRdfType('http://xmlns.com/foaf/0.1/Person');
										
										// given name
										$givenNames = array();
										$subElements = $xpath->query("qr:given_name", $element);
										foreach($subElements as $subElement)
										{
											/* @var $subElement DOMNode */
											$givenNames[] = $subElement->nodeValue;
										}
										$person->addStatement('http://xmlns.com/foaf/0.1/givenName', $givenNames);

										// family name
										$familyNames = array();
										$subElements = $xpath->query("qr:surname", $element);
										foreach($subElements as $subElement)
										{
											/* @var $subElement DOMNode */
											$familyNames[] = $subElement->nodeValue;
										}
										$person->addStatement('http://xmlns.com/foaf/0.1/familyName', $familyNames);
										
										// suffix
										$suffixes = array();
										$subElements = $xpath->query("qr:suffix", $element);
										foreach($subElements as $subElement)
										{
											/* @var $subElement DOMNode */
											$suffixes[] = $subElement->nodeValue;
										}
										$person->addStatement('http://xmlns.com/foaf/0.1/title', $suffixes);
										
										// combined name
										$name = trim(implode(' ', $suffixes) . ' ' . implode(' ', $givenNames) . ' ' . implode(' ', $familyNames));
										if($name != '')
										{
											$person->addStatement('http://xmlns.com/foaf/0.1/name', $name);
										}

										if($contributorRole->nodeValue == 'author')
										{
											$rdfResource->addStatement('http://purl.org/dc/terms/creator', $person->getSubject());
										}
										else
										{
											$rdfResource->addStatement('http://purl.org/dc/terms/contributor', $person->getSubject());
										}
									}
								}
								
								// year of publication
								$elements = $xpath->query("qr:year", $queryElement);
								if($elements->length > 0)
								{
									$objects = array();
									foreach($elements as $element)
									{
										/* @var $element DOMNode */
										$objects[] = $element->nodeValue;
									}
									$rdfResource->addStatement('http://purl.org/dc/terms/issued', $objects);
								}
								
								if(count($rdfResource->getPredicates()) > 0)
								{
									$metadataDocuments[] = $rdfDocument;
								}
							}
						}
					}
				}
			}
		}

		// create the result objects
		foreach($metadataDocuments as $metadataDocument)
		{
			$result = new metaextractor_Result();
			$result->setExtractorId($this->getId());
			$result->setExtractorName($this->getName());
			$result->setSubjectUri($subjectUri);
			$result->setRdfDocument($metadataDocument);
			
			$results[] = $result;
		}
		
		return $results;
	}
}